package com.znjc.iot.task;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * 定时任务管理器
 *
 * @author Admin
 */
@Slf4j
@Component
@RequiredArgsConstructor
@Data
public class ScheduleManager {
    @Resource
    private ThreadPoolTaskScheduler taskScheduler;

    /**
     * 内部正在执行的定时任务缓存，key为串口id
     */
    private final Map<Long, CollectDataTaskHolder> cache = new ConcurrentHashMap<>();

    /**
     * 启动一个定时任务
     *
     * @param scheduleTask 定时任务
     * @param corn         执行周期 corn表达式
     */
    public void startTask(CollectDataTask scheduleTask, String corn) {
        //获取设备id
        Long serialId = scheduleTask.getSerialId();
        //检查该设备是否已在执行数据采集定时任务
        CollectDataTaskHolder scheduleTaskHolder = cache.get(serialId);
        if (scheduleTaskHolder != null) {
            throw new RuntimeException("该设备类型已在进行数据采集");
        }
        //开始执行任务
        ScheduledFuture<?> scheduledFuture = taskScheduler.schedule(scheduleTask, new CronTrigger(corn));
        //封装定时任务和执行结果
        CollectDataTaskHolder newHolder = new CollectDataTaskHolder(scheduleTask, scheduledFuture);
        //将正在执行的定时任务缓存起来
        cache.put(serialId, newHolder);
        log.info("定时任务启动成功，串口id为{}", serialId);
    }


    /**
     * 停止一个定时任务
     *
     * @param serialId：串口id
     */
    public void stopTask(Long serialId) {
        //从缓存中拿到这个定时任务
        CollectDataTaskHolder scheduleTaskHolder = cache.get(serialId);
        if (scheduleTaskHolder == null) {
            return;
        }
        ScheduledFuture<?> scheduledFuture = scheduleTaskHolder.getScheduledFuture();
        //停止这个定时任务
        boolean isCancel = scheduledFuture.cancel(true);
        if (isCancel) {
            //停止成功，就从缓存中移除这个定时任务
            cache.remove(serialId);
            log.info("定时任务停止成功，串口id为{}", serialId);
        } else {
            log.error("定时任务停止失败，串口id为{}", serialId);
        }
    }

    /**
     * 修改执行中的定时任务的采集周期
     *
     * @param serialId 串口id
     * @param corn  新的采集周期
     */
    public void changeTask(Long serialId, String corn) {
        //检查执行中的任务中是否有该设备
        CollectDataTaskHolder scheduleTaskHolder = cache.get(serialId);
        //设备当前未进行采集，不需要重启定时任务
        if (scheduleTaskHolder == null) {
            return;
        }
        //先停止这个定时任务
        stopTask(serialId);
        //然后重启开启一个定时任务
        startTask(scheduleTaskHolder.getCollectDataTask(), corn);
    }

}
